<template>
  <div :class="classes" :style="listStyle" ref="transferListRef">
    <div :class="prefixCls + '-header'">
      <e-checkbox
        :indeterminate="isIndeterminate"
        :modelValue="checkedAll"
        :disabled="checkedAllDisabled"
        @update:modelValue="toggleSelectAll"
      ></e-checkbox>
      <span :class="prefixCls + '-header-title'" @click="toggleSelectAll(!checkedAll)">{{ title }}</span>
      <span :class="prefixCls + '-header-count'">{{ count }}</span>
    </div>
    <div :class="bodyClasses">
      <div :class="prefixCls + '-body-search-wrapper'" v-if="filterable">
        <Search
          :prefix-cls="prefixCls + '-search'"
          :query="query"
          @on-query-clear="handleQueryClear"
          @on-query-change="handleQueryChange"
          :placeholder="filterPlaceholder"></Search>
      </div>
      <ul :class="prefixCls + '-content'" v-if="!asTable">
        <li
          v-for="(item, index) in filterData"
          :key="index"
          :class="itemClasses(item)"
          @click.prevent="select(item)">
          <e-checkbox :modelValue="isCheck(item)" :disabled="item.disabled"></e-checkbox>
          <div v-html="showLabel(item)"></div>
        </li>
        <li :class="prefixCls + '-content-not-found'">{{ notFoundText }}</li>
      </ul>
      <div
        :class="prefixCls + '-content as-table'"
        v-else>
        <e-table
          :columns="columns"
          :data="filterData"
          :max-height="tableHeight"
          @on-select="onTableSelect"
          @on-select-cancel="onTableSelectCancel"
          @on-select-all="onTableSelectAll"
          @on-select-all-cancel="onTableSelectAllCancel" />
      </div>
    </div>
    <div :class="prefixCls + '-footer'" ref="transferListFooterRef" v-if="showFooter"><slot></slot></div>
  </div>
</template>
<script>
import Search from './search.vue';
export default {
  name: 'TransferList',
  components: { Search },
  inject: ['TransferInstance'],
  emits: ['on-checked-keys-change'],
  props: {
    prefixCls: String,
    data: Array,
    renderFormat: Function,
    checkedKeys: Array,
    listStyle: Object,
    title: [String, Number],
    filterable: Boolean,
    filterPlaceholder: String,
    filterMethod: Function,
    notFoundText: String,
    validKeysCount: Number,
    asTable: Boolean,
    columns: Array,
    showFooter: Boolean,
  },
  data () {
    return {
      showItems: [],
      query: '',
      tableHeight: 0
    };
  },
  watch: {
    data () {
      this.updateFilteredData();
    }
  },
  computed: {
    classes () {
      return [
        `${this.prefixCls}`,
        {
          [`${this.prefixCls}-with-footer`]: this.showFooter
        }
      ];
    },
    bodyClasses () {
      return [
        `${this.prefixCls}-body`,
        {
          [`${this.prefixCls}-body-with-search`]: this.filterable,
          [`${this.prefixCls}-body-with-footer`]: this.showFooter
        }
      ];
    },
    count () {
      return `(${this.data.length}项)`;
    },
    checkedAll () {
      return this.filterData.filter(data => !data.disabled).length === this.validKeysCount && this.validKeysCount !== 0;
    },
    checkedAllDisabled () {
      return this.filterData.filter(data => !data.disabled).length <= 0;
    },
    filterData () {
      return this.showItems.filter(item => this.filterMethod(item, this.query));
    },
    isIndeterminate () {
      const enableData = this.data.filter((item) => !item.disabled);
      return this.checkedKeys !== 0 && enableData.length > this.checkedKeys.length;
    }
  },
  methods: {
    itemClasses (item) {
      return [
        `${this.prefixCls}-content-item`,
        {
          [`${this.prefixCls}-content-item-disabled`]: item.disabled
        }
      ];
    },
    showLabel (item) {
      return this.renderFormat(item);
    },
    isCheck (item) {
      return this.checkedKeys.some(key => key === item.key);
    },
    select (item) {
      if (item.disabled) return;
      const index = this.checkedKeys.indexOf(item.key);
      // eslint-disable-next-line vue/no-mutating-props
      index > -1 ? this.checkedKeys.splice(index, 1) : this.checkedKeys.push(item.key);
      this.TransferInstance.handleCheckedKeys();
    },
    updateFilteredData () {
      this.showItems = this.data;
    },
    toggleSelectAll (status) {
      const keys = status ?
        this.filterData.filter(data => !data.disabled || this.checkedKeys.indexOf(data.key) > -1).map(data => data.key) :
        this.filterData.filter(data => data.disabled && this.checkedKeys.indexOf(data.key) > -1).map(data => data.key);
      this.$emit('on-checked-keys-change', keys);
    },
    onTableSelect (selection, row) {
      // eslint-disable-next-line vue/no-mutating-props
      this.checkedKeys.push(row.key);
      this.$parent.handleCheckedKeys();
    },
    onTableSelectCancel (selection, row) {
      // eslint-disable-next-line vue/no-mutating-props
      this.checkedKeys.splice(this.checkedKeys.indexOf(row.key), 1);
      this.$parent.handleCheckedKeys();
    },
    onTableSelectAll (event) {
      const keys = this.filterData.filter(data => !data._disabled || this.checkedKeys.indexOf(data.key) > -1).map(data => data.key);
      this.$emit('on-checked-keys-change', keys);
    },
    onTableSelectAllCancel () {
      const keys = this.filterData.filter(data => data._disabled && this.checkedKeys.indexOf(data.key) > -1).map(data => data.key);
      this.$emit('on-checked-keys-change', keys);
    },
    handleQueryClear () {
      this.query = '';
    },
    handleQueryChange (val) {
      this.query = val;
    }
  },
  created () {
    this.updateFilteredData();
  },
  mounted () {
    let filterHeight = this.filterable ? 40 : 0;
    let footerHeight = this.$refs.transferListFooterRef ? this.$refs.transferListFooterRef.offsetHeight : 0;
    this.tableHeight = this.$refs.transferListRef.offsetHeight - 32 - filterHeight - 8 - 10 - footerHeight;
  }
};
</script>
